package main

import (
	"fmt"
	"math"
	"time"
)

func sum(data []int) int {
	total := 0
	for _, v := range data {
		total += v
	}
	return total
}

func half_int(a int) (r int, f bool) {
	r = a / 2
	if a%2 == 0 {
		f = true
	} else {
		f = false
	}
	return
}

func average(xs []float64) float64 {
	var total float64 = 0
	for _, v := range xs {
		total += v
	}
	return total / float64(len(xs))
}

func max(args ...int) (ret int) {
	ret = 0
	for _, v := range args {
		if v > ret {
			ret = v
		}
	}
	return
}

func makeEvenGerator() func() uint {
	i := uint(0)
	return func() (ret uint) {
		ret = i
		i += 2
		return
	}
}

func test_defer() (int, error) {
	defer fmt.Println(("3nd"))
	fmt.Println("1st")
	return fmt.Println("2th")
}

func test_recover() {
	defer func() {
		str := recover()
		fmt.Println(str)
	}()
	panic("PANIC")
	fmt.Println("Never run here")
}

func fibonacci(n int) int {
	if n == 0 {
		return 0
	} else if n == 1 {
		return 1
	}
	return fibonacci(n-1) + fibonacci(n-2)
}

type Circle struct {
	x float64
	y float64
	r float64
}

func (c Circle) area() float64 {
	c.x = 20
	return math.Pi * c.r * c.r
}

type Person struct {
	name string
}

func (p *Person) talk() {
	fmt.Println("Hello, I'm ", p.name)
}

type Android struct {
	Person
	model string
}

func pinger(c chan string) {
	for {
		fmt.Println("pinger send a message")
		c <- "ping"
	}
}

func ponger(c chan string) {
	for {
		fmt.Println("ponger send a message")
		c <- "pong"
	}
}

func printer(c chan string) {
	for {
		msg := <-c
		fmt.Println("printer get a message: ", msg)
		time.Sleep(time.Second * 2)
	}
}

func test_slice() {
	array := [5]int{5, 3, 2, 34, 1}
	array[0] = 10
	a := array[0:2]
	fmt.Println(a)
	fmt.Printf("before change: %v\n", array)
	a[0] = 10
	fmt.Printf("after change: %v\n", array)
}

func main() {
	fmt.Printf("Basic Demo\n")

	test_slice()

	xs := []float64{98, 93, 77, 82, 83}
	fmt.Println(average(xs))

	nextEvne := makeEvenGerator()
	fmt.Println(nextEvne())
	fmt.Println(nextEvne())
	fmt.Println(nextEvne())

	test_defer()
	test_recover()

	fmt.Println(half_int(1))
	fmt.Println(half_int(2))
	fmt.Println(max(2, 3, 2, 5, 6, 8, 9, 1, 232, 56, 2))
	fmt.Println(fibonacci(10))

	c := Circle{0, 0, 5}
	fmt.Println(c.area())

	fmt.Println(c.x)

	a := new(Android)
	a.talk()

	{
		var c chan string = make(chan string)
		go pinger(c)
		go ponger(c)
		go printer(c)
	}

	c1 := make(chan string)
	c2 := make(chan string)
	go func() {
		for {
			c1 <- "from 1"
			time.Sleep(time.Second * 6)
		}
	}()

	go func() {
		for {
			c2 <- "from 2"
			time.Sleep(time.Second * 8)
		}
	}()

	go func() {
		for {
			select {
			case msg1 := <-c1:
				fmt.Println(msg1)
			case msg2 := <-c2:
				fmt.Println(msg2)
			case t := <-time.After(time.Second):
				fmt.Println("timeout : ", t)
			}
		}
	}()

	var input string
	fmt.Scanln(&input)
}
